﻿// cfg_encode.cpp : Defines the entry point for the console application.
//
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <iostream>
#include <direct.h> 
#include <string>
#include <vector>
#include "boost/filesystem/operations.hpp"
#include "boost/filesystem/path.hpp"
#include "boost/filesystem/operations.hpp"
#include "boost/filesystem/fstream.hpp"
#include <locale.h>
std::vector<std::string> EnumFiles(std::string path, std::string extension)
{
	namespace fs = boost::filesystem;
	fs::path _path(path);
	fs::path fullpath = fs::system_complete(_path);

	std::vector<std::string> ret;

	if (!fs::exists(fullpath) && !fs::is_directory(fullpath))
	{
		return ret;
	}
	fs::directory_iterator end_iter;
	for (fs::directory_iterator iter(fullpath); iter != end_iter; iter++)
	{
		try {
			if (fs::is_directory(*iter))
			{
				//ret.push_back(iter->path().wstring());
			}
			else if (iter->path().extension() == extension)
			{
				ret.push_back(iter->path().string());
			}
		}
		catch (const std::exception&)
		{
			continue;
		}
	}
	return ret;
}
const int MIN_ASC = 32;// ' Space.
const int MAX_ASC = 126;// ' ~.
const int NUM_ASC = MAX_ASC - MIN_ASC + 1;//

char encodedecode(char* str, char seed, int n)
{
	int i;
	int _seed = seed;
	for (i = 0; i < n; i++, str++)
	{
		if (*str >= MIN_ASC && *str <= MAX_ASC)
		{
			*str = MIN_ASC + ((_seed + int(*str) - MIN_ASC) % NUM_ASC);

			_seed++;
			if (_seed == 10)
			{
				_seed = 0;
			}
		}
	}
	return _seed;
}

bool ReadFileBinary(const char* file_path, std::vector<char>& v_data)
{
	v_data.clear();

	namespace bf = boost::filesystem;
	std::string str_path = file_path;
	bf::path path(str_path);
	if (bf::exists(path) && bf::is_regular_file(path))
	{
		bf::ifstream file(path, std::ios::in | std::ios::binary);
		if (file)
		{
			file.seekg(0, std::ios::end);
			bf::ifstream::pos_type _size = file.tellg();
			v_data.resize(_size);
			file.seekg(0, std::ios::beg);
			file.read(&v_data[0], std::streamsize(_size));
			file.close();
			return true;
		}
	}
	return false;
}
bool WriteFileBinary(const char* file_path, std::vector<char>& v_data)
{
	try
	{
		namespace bf = boost::filesystem;
		std::string str_path = file_path;
		bf::path path(str_path);
		if (!bf::exists(path.parent_path()))
		{
			bf::create_directory(path.parent_path());
		}
		bf::remove(path);
		bf::ofstream file(path, std::ios::out | std::ios::binary);
		if (file)
		{
			file.write(&v_data[0], std::streamsize(v_data.size()));
			file.flush();
			return true;
		}
		return false;
	}
	catch (std::exception* e)
	{
		return false;
	}
}
void* xmalloc(size_t size) {
	void* ptr = malloc(size);
	if (!ptr) {
		fprintf(stderr, "xMalloc error - possibly out of CPU RAM \n");
	}
	return ptr;
}

void* xrealloc(void* ptr, size_t size) {
	ptr = realloc(ptr, size);
	if (!ptr) {
		fprintf(stderr, "Realloc error - possibly out of CPU RAM \n");
	}
	return ptr;
}


char* fgetl_encrypt(FILE* fp)
{
	if (feof(fp)) return 0;
	size_t size = 512;
	char* line = (char*)xmalloc(size * sizeof(char));
	if (!fgets(line, size, fp)) {
		free(line);
		return 0;
	}

	size_t curr = strlen(line);
	char seed = 5;
	seed = encodedecode(line, seed, curr);
	while ((line[curr - 1] != '\n') && !feof(fp)) {
		if (curr == size - 1) {
			size *= 2;
			line = (char*)xrealloc(line, size * sizeof(char));
		}
		size_t readsize = size - curr;
		if (readsize > INT_MAX) readsize = INT_MAX - 1;
		fgets(&line[curr], readsize, fp);
		curr = strlen(line);
		seed = encodedecode(line, seed, curr);
	}
	return line;
}

void TransCfg(std::string src_path, std::string dest_path)
{
	FILE* src_file = fopen(src_path.c_str(), "r");
	if (src_file == 0)
	{
		fprintf(stderr, "Couldn't open file: %s\n", src_path.c_str());
	}
	FILE* dest_file = fopen(dest_path.c_str(), "w");
	if (dest_file == 0)
	{
		fprintf(stderr, "Couldn't open file: %s\n", src_path.c_str());
	}
	char* src_line;
	while ((src_line = fgetl_encrypt(src_file)) != 0) {
		fputs(src_line, dest_file);
		free(src_line);
	}
	fclose(src_file);
	fclose(dest_file);

	fprintf(stderr, "trans %s to %s \n", src_path.c_str(), dest_path.c_str());
}

void TransWeight(std::string src_path, std::string dest_path)
{
	std::vector<char> v_data;
	ReadFileBinary(src_path.c_str(), v_data);
	for (int i = 0; i < v_data.size(); ++i)
	{
		v_data[i] = (~v_data[i] + 0x35);
	}
	WriteFileBinary(dest_path.c_str(), v_data);
	fprintf(stderr, "trans %s to %s \n", src_path.c_str(), dest_path.c_str());
}

int main(int argc, char* argv[])
{
	//setlocale(LC_ALL, "chs");

	namespace fs = boost::filesystem;

	try
	{
		char cur_folder[260];
		_getcwd(cur_folder, sizeof(cur_folder));

		std::string cwd = cur_folder;
		std::string mon_folder = cwd;
		std::string dest_folder = cwd;
		std::string mark_info = "";
		if (argc >= 2)
		{
			mon_folder = argv[1];
			dest_folder = mon_folder;
		}
		if (argc >= 3)
		{
			dest_folder = argv[2];
		}
		if (argc >= 4)
		{
			mark_info = argv[3];
		}
		printf("model directory: %s\n", mon_folder);
		printf("trans directory: %s\n", dest_folder);

		//===================================================================================================
		std::vector<std::string> dat_files = EnumFiles(mon_folder, std::string(".cfg"));

		for (int i = 0; i < dat_files.size(); ++i)
		{
			std::string src_file = dat_files[i];

			fs::path _path(src_file);
			_path.replace_extension("dat");
			std::string dest_file = dest_folder + std::string("\\") + _path.filename().string();
			if (!fs::exists(dest_file))
			{
				TransCfg(src_file, dest_file);
			}
		}
		//======================================================================================================
		dat_files = EnumFiles(mon_folder, std::string(".weights"));
		for (int i = 0; i < dat_files.size(); ++i)
		{
			std::string src_file = dat_files[i];

			fs::path _path(src_file);
			_path.replace_extension("dats");
			std::string dest_file = dest_folder + std::string("\\") + _path.filename().string();
			if (!fs::exists(dest_file))
			{
				TransWeight(src_file, dest_file);
			}
		}
		std::cout << "Done!";
	}
	catch (...)
	{
	}
	for (int i = 0; i < 5; ++i)
	{
		std::this_thread::sleep_for(std::chrono::milliseconds(1000));
		//printf("wait for shutdown %d !\n", 5 - i);
	}
	//getchar();
	return 0;
}

